//-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   ifdiv
//File Name     :   float_format.v
//Module name   :   float format
//Full name     :   float number format transfering 
//
//Author        :   xiang tian
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.01
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//1.01: fix dedorminate number exp bugs, add busy port
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//----------------------------- 
module float_format(
    clk,
    rst_n,
    busy,
    en,
    din,
    type_i,
    sign,
    exp,
    man,
    iszero,
    isinf,
    isnan,
    valid
);


input             clk;
input             rst_n;
input             busy;
input             en;
input      [31:0] din;
input      [1:0]  type_i;
output reg        sign;
output reg [8:0]  exp;
output reg [30:0] man;
output reg        iszero;
output reg        isinf;
output reg        isnan;
output reg        valid;


wire [32:0]  int_number;
wire [31:0]  float_number;
wire         isfloat;

assign isfloat = type_i[1];


assign int_number = (type_i == 2'b00) ? {1'b0,din} :
                    (type_i == 2'b01) ? {din[31],din} :
                    33'b1;

assign float_number = (type_i[1] == 1'b1) ? din : 32'h80_0000;

//--------------------------------------------------------------------------------------
// get integer exponent & mantissa
//--------------------------------------------------------------------------------------


reg [8:0]   exp_int;
reg [30:0]  man_int;
wire        sign_int;
wire [31:0] pos_int;
reg         zero_int;


assign  sign_int = int_number[32];
assign  pos_int = (sign_int == 0 ) ? int_number : (~int_number + 1'b1);

always@*
begin
    casex(pos_int)
        32'b0000_0000_0000_0000_0000_0000_0000_0000: begin exp_int = 9'd0 ; man_int = 31'b0                ; zero_int = 1'b1; end
        32'b0000_0000_0000_0000_0000_0000_0000_0001: begin exp_int = 9'd0 ; man_int = 31'b0                ; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_0000_001x: begin exp_int = 9'd1 ; man_int = {pos_int[ 0]  ,30'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_0000_01xx: begin exp_int = 9'd2 ; man_int = {pos_int[ 1:0],29'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_0000_1xxx: begin exp_int = 9'd3 ; man_int = {pos_int[ 2:0],28'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_0001_xxxx: begin exp_int = 9'd4 ; man_int = {pos_int[ 3:0],27'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_001x_xxxx: begin exp_int = 9'd5 ; man_int = {pos_int[ 4:0],26'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_01xx_xxxx: begin exp_int = 9'd6 ; man_int = {pos_int[ 5:0],25'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0000_1xxx_xxxx: begin exp_int = 9'd7 ; man_int = {pos_int[ 6:0],24'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_0001_xxxx_xxxx: begin exp_int = 9'd8 ; man_int = {pos_int[ 7:0],23'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_001x_xxxx_xxxx: begin exp_int = 9'd9 ; man_int = {pos_int[ 8:0],22'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_01xx_xxxx_xxxx: begin exp_int = 9'd10; man_int = {pos_int[ 9:0],21'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0000_1xxx_xxxx_xxxx: begin exp_int = 9'd11; man_int = {pos_int[10:0],20'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_0001_xxxx_xxxx_xxxx: begin exp_int = 9'd12; man_int = {pos_int[11:0],19'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_001x_xxxx_xxxx_xxxx: begin exp_int = 9'd13; man_int = {pos_int[12:0],18'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_01xx_xxxx_xxxx_xxxx: begin exp_int = 9'd14; man_int = {pos_int[13:0],17'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0000_1xxx_xxxx_xxxx_xxxx: begin exp_int = 9'd15; man_int = {pos_int[14:0],16'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_0001_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd16; man_int = {pos_int[15:0],15'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_001x_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd17; man_int = {pos_int[16:0],14'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_01xx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd18; man_int = {pos_int[17:0],13'b0}; zero_int = 1'b0; end
        32'b0000_0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd19; man_int = {pos_int[18:0],12'b0}; zero_int = 1'b0; end
        32'b0000_0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd20; man_int = {pos_int[19:0],11'b0}; zero_int = 1'b0; end
        32'b0000_0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd21; man_int = {pos_int[20:0],10'b0}; zero_int = 1'b0; end
        32'b0000_0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd22; man_int = {pos_int[21:0], 9'b0}; zero_int = 1'b0; end
        32'b0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd23; man_int = {pos_int[22:0], 8'b0}; zero_int = 1'b0; end
        32'b0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd24; man_int = {pos_int[23:0], 7'b0}; zero_int = 1'b0; end
        32'b0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd25; man_int = {pos_int[24:0], 6'b0}; zero_int = 1'b0; end
        32'b0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd26; man_int = {pos_int[25:0], 5'b0}; zero_int = 1'b0; end
        32'b0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd27; man_int = {pos_int[26:0], 4'b0}; zero_int = 1'b0; end
        32'b0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd28; man_int = {pos_int[27:0], 3'b0}; zero_int = 1'b0; end
        32'b001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd29; man_int = {pos_int[28:0], 2'b0}; zero_int = 1'b0; end
        32'b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd30; man_int = {pos_int[29:0], 1'b0}; zero_int = 1'b0; end
        32'b1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_int = 9'd31; man_int =  pos_int[30:0]       ; zero_int = 1'b0; end
        default:                                     begin exp_int = 9'd0 ; man_int = 31'b0                ; zero_int = 1'b1; end
    endcase
end

//--------------------------------------------------------------------------------------
// get float exponent & mantissa & exception
//--------------------------------------------------------------------------------------
 
wire [8:0]  exp_float;
wire [30:0] man_float;

wire        sign_float;
wire        zero_float;
wire        nan_float;
wire        inf_float;
wire        denorm_float;

assign      sign_float = float_number[31];
assign      zero_float = (float_number[30:0] == 31'b0)? 1'b1 : 1'b0;       //32'h0000_0000 or 32'h8000_0000
assign      nan_float = ((float_number[30:23] == 8'hff) && (float_number[22:0] != 23'b0)) ? 1'b1 : 1'b0; //32'h7f8x_xxxx or 32'hff8x_xxxx
assign      inf_float = ((float_number[30:23] == 8'hff) && (float_number[22:0] == 23'b0)) ? 1'b1 : 1'b0; //32'h7f80_0000 or 32'hff80_0000
assign      denorm_float = ((float_number[30:23] == 8'b0) && (float_number[22:0] != 23'b0)) ? 1'b1 : 1'b0; //32'h00Xx_xxxx or 32'h800Xx_xxxx  



//--------------------------------------------------------------------------------------
// calc demormalized number
//--------------------------------------------------------------------------------------

reg [9:0]  exp_denorm;
reg [30:0] man_denorm;


always @*
begin
    casex(float_number[22:0])
        23'b000_0000_0000_0000_0000_0001: begin exp_denorm = 9'd23; man_denorm = 31'b0;                      end
        23'b000_0000_0000_0000_0000_001x: begin exp_denorm = 9'd22; man_denorm = {float_number[ 0]  ,30'b0}; end
        23'b000_0000_0000_0000_0000_01xx: begin exp_denorm = 9'd21; man_denorm = {float_number[ 1:0],29'b0}; end
        23'b000_0000_0000_0000_0000_1xxx: begin exp_denorm = 9'd20; man_denorm = {float_number[ 2:0],28'b0}; end
        23'b000_0000_0000_0000_0001_xxxx: begin exp_denorm = 9'd19; man_denorm = {float_number[ 3:0],27'b0}; end
        23'b000_0000_0000_0000_001x_xxxx: begin exp_denorm = 9'd18; man_denorm = {float_number[ 4:0],26'b0}; end
        23'b000_0000_0000_0000_01xx_xxxx: begin exp_denorm = 9'd17; man_denorm = {float_number[ 5:0],25'b0}; end
        23'b000_0000_0000_0000_1xxx_xxxx: begin exp_denorm = 9'd16; man_denorm = {float_number[ 6:0],24'b0}; end
        23'b000_0000_0000_0001_xxxx_xxxx: begin exp_denorm = 9'd15; man_denorm = {float_number[ 7:0],23'b0}; end
        23'b000_0000_0000_001x_xxxx_xxxx: begin exp_denorm = 9'd14; man_denorm = {float_number[ 8:0],22'b0}; end
        23'b000_0000_0000_01xx_xxxx_xxxx: begin exp_denorm = 9'd13; man_denorm = {float_number[ 9:0],21'b0}; end
        23'b000_0000_0000_1xxx_xxxx_xxxx: begin exp_denorm = 9'd12; man_denorm = {float_number[10:0],20'b0}; end
        23'b000_0000_0001_xxxx_xxxx_xxxx: begin exp_denorm = 9'd11; man_denorm = {float_number[11:0],19'b0}; end
        23'b000_0000_001x_xxxx_xxxx_xxxx: begin exp_denorm = 9'd10; man_denorm = {float_number[12:0],18'b0}; end
        23'b000_0000_01xx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd9 ; man_denorm = {float_number[13:0],17'b0}; end
        23'b000_0000_1xxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd8 ; man_denorm = {float_number[14:0],16'b0}; end
        23'b000_0001_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd7 ; man_denorm = {float_number[15:0],15'b0}; end
        23'b000_001x_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd6 ; man_denorm = {float_number[16:0],14'b0}; end
        23'b000_01xx_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd5 ; man_denorm = {float_number[17:0],13'b0}; end
        23'b000_1xxx_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd4 ; man_denorm = {float_number[18:0],12'b0}; end
        23'b001_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd3 ; man_denorm = {float_number[19:0],11'b0}; end
        23'b01x_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd2 ; man_denorm = {float_number[20:0],10'b0}; end
        23'b1xx_xxxx_xxxx_xxxx_xxxx_xxxx: begin exp_denorm = 9'd1 ; man_denorm = {float_number[21:0], 9'b0}; end
        default:                          begin exp_denorm = 9'd0 ; man_denorm = 31'b0;                      end
    endcase
end


assign   exp_float =  (zero_float || nan_float || inf_float) ? 9'b0 :
                      denorm_float ? ({1'b0,float_number[30:23]} - 9'd126 - exp_denorm) :   //denormalized number
                      ({1'b0,float_number[30:23]}-9'd127) ;                                 //normalized number

assign   man_float =  (zero_float || nan_float || inf_float) ? 31'b0 :                                             
                      denorm_float ? man_denorm :               //denormalized number 
                      {float_number[22:0],8'b0};                //normalized number   

//-----------------------------------------------------------------------------
//ouput
//-----------------------------------------------------------------------------

wire        sign_out;
wire [8:0]  exp_out;
wire [30:0] man_out;
wire        zero_out;
wire        nan_out;
wire        inf_out;    

assign sign_out = isfloat ? sign_float : sign_int;
assign exp_out = isfloat ? exp_float : exp_int;
assign man_out = isfloat ? man_float : man_int;
assign zero_out = isfloat ? zero_float : zero_int;
assign nan_out = isfloat & nan_float;
assign inf_out = isfloat & inf_float;


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        sign   <= 1'b0;
        exp    <= 9'b0;
        man    <= 31'b0;
        iszero <= 1'b0;
        isinf  <= 1'b0;
        isnan  <= 1'b0;
    end
    else if(en && !busy)
    begin
        sign   <= sign_out;
        exp    <= exp_out;
        man    <= man_out;
        iszero <= zero_out;
        isinf  <= inf_out;
        isnan  <= nan_out;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)     valid <= 1'b0;
    else if(!busy) valid <= en;
end                    



endmodule
